//
// Created by denglibin on 2021/8/12.
//


#include <wx/app.h>
#include <wx/wx.h>
#include <wx/wxprec.h>
#include <string>
#include <wx/dcbuffer.h>
using namespace std;
/**
 * 内存设备上下文(wxMemoryDC)是和一个位图绑定的设备上下文，在这个设备上下文上的所有绘画都将画
在那个位图上面。使用的方法是先使用默认的构造函数创建一个内存设备上下文，然后使用SelectObject函数将其和一个位图绑定，
 在完成所有的绘画以后再调用SelectObject函数参数为
wxNullBitmap来移除绑定的位图，
 */
class MemDcFrame : public wxFrame
{
private:
    //声明事件表
    DECLARE_EVENT_TABLE();

    /**
     * 线条
     * @param memDC
     */
    static void drawLine(wxMemoryDC& memDC){

        double r = 5;
        wxCoord x, y, lstX, lstY;
        for (int a = 0; a <= 720; ++ a) {
            double b = a * 3.1415 / 180;//角度转弧度
            x = cos(b) * r;
            y = sin(b) * r;
            if(a != 0) {
                memDC.DrawLine(400 + x, 300 + y, 400 + lstX, 300 + lstY);
            }
            r += 0.25;
            lstX = x;
            lstY = y;
        }
    }
    /**
     * 绘制文字
     * @param memDC
     * @param dc
     */
    static void drawText(wxMemoryDC& memDC, wxPaintDC& dc){
        //字体
        //  wxFont font(wxSystemSettings::GetFont(wxSystemFont::wxSYS_DEFAULT_GUI_FONT));
        //wxFont font(wxFontInfo(25).Bold(true).FaceName(wxT("STCAIYUN"))); //华文云彩
        //memDC.SetFont(font);
        memDC.SetTextForeground(*wxWHITE);//颜色

        memDC.DrawText(wxT("By luoluolzb"), 5, 5);
        memDC.DrawRotatedText(wxT("我是谁"), 100, 10, -60); //有旋转角度的文字

        //绘制文字
        wxString msg = wxT("Some text will appear mixed in the image's shadow...");
        int y = 75;
        for (size_t i = 0; i < 10; i++)
        {
            y += dc.GetCharHeight() + 5;
            memDC.DrawText(msg, 200, y);
        }
    }

    /**
     * 绘制形状
     * @param memDC
     */
    static void drawShape(wxMemoryDC& memDC){

        memDC.DrawRectangle(500,50, 100,50); //画矩形

        // 画圆角矩形
        memDC.DrawRoundedRectangle(150, 150, 100, 50, 10);
        // 画一个椭圆
        memDC.DrawEllipse(wxRect(150, 80, 150, 50));

        // 没有轮廓线的圆角矩形
        memDC.SetPen(*wxTRANSPARENT_PEN);
        memDC.DrawRoundedRectangle(150, 250, 100, 50, 10);
    }

    /**
     * 多段线
     * @param memDC
     */
    static void drawPolyPolygon(wxMemoryDC& memDC){
        //多段线 五角星
        memDC.SetPen(*wxRED_PEN);
        wxPoint star[5];
        star[0] = wxPoint(100, 60);
        star[1] = wxPoint(60, 150);
        star[2] = wxPoint(160, 100);
        star[3] = wxPoint(40, 100);
        star[4] = wxPoint(140, 150);
        memDC.DrawPolygon(WXSIZEOF(star), star, 0, 30);
        memDC.DrawPolygon(WXSIZEOF(star), star, 300, -15, wxPolygonFillMode::wxWINDING_RULE);

        wxPoint star2[10];
        star2[0] = wxPoint(0, 100);
        star2[1] = wxPoint(-59, -81);
        star2[2] = wxPoint(95, 31);
        star2[3] = wxPoint(-95, 31);
        star2[4] = wxPoint(59, -81);
        star2[5] = wxPoint(0, 80);
        star2[6] = wxPoint(-47, -64);
        star2[7] = wxPoint(76, 24);
        star2[8] = wxPoint(-76, 24);
        star2[9] = wxPoint(47, -64);
        int count[2] = {5, 5};
        memDC.DrawPolyPolygon(WXSIZEOF(count), count, star2, 600, 150);
    }
    /**
     * 双缓冲绘图
     * @param event
     */
    void OnPaint_(wxPaintEvent & event){

        /* wxPaintDC 只能放在函数内*/
        wxPaintDC dc(this);
        //获取窗口大小
        //wxSize size = this->GetClientSize();
        /* 准备wxMemoryDC */
        wxMemoryDC memDC;
        wxRect win_rect = this->GetRect();
        wxBitmap bitmap(win_rect.GetSize());
        memDC.SelectObject(bitmap);

        /* 开始绘图 */
        memDC.SetPen(*wxYELLOW);
        //memDC.SetBrush(*wxYELLOW_BRUSH);
        wxColour backGroundColor(0,100,0);
        memDC.SetBackground(backGroundColor);
        memDC.Clear();//使用当前的背景刷刷新背景

        drawLine(memDC);
        drawText(memDC, dc);

        //设置画笔和画刷
        wxPen pen;
        pen.SetColour(wxColour(255,0,0));//画笔颜色
        pen.SetWidth(2);//宽度
        pen.SetStyle(wxPenStyle::wxPENSTYLE_DOT); //线型
        memDC.SetPen(pen);
        // wxColour color(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
        wxBrush brush; //画刷
        brush.SetColour(wxColour(255,255,0)); //颜色
        brush.SetStyle(wxBrushStyle::wxBRUSHSTYLE_CROSSDIAG_HATCH);//样式
        memDC.SetBrush(brush);

        drawShape(memDC);

        drawPolyPolygon(memDC);

        //绘制平滑曲线
        // 三点云行规曲线
        memDC.DrawSpline(10, 100, 200, 200, 50, 230);

        // 五点云行规曲线
        wxPoint star3[5];
        star3[0] = wxPoint(100, 60);
        star3[1] = wxPoint(60, 150);
        star3[2] = wxPoint(160, 100);
        star3[3] = wxPoint(40, 100);
        star3[4] = wxPoint(140, 150);
        memDC.SetPen(*wxBLACK_PEN);
        memDC.DrawSpline(WXSIZEOF(star3), star3);


        //绘制位图
        wxBitmap bmp("resources/favorites-filling.png", wxBITMAP_TYPE_PNG); //  构造方法中加入 wxImage::AddHandler(new wxPNGHandler);
        memDC.DrawBitmap(bmp, 250, 100, true);

        /* 绘图完毕 */
        /* 复制到wxPaintDC,Blit函数将内存设备上下文中的某一个区域拷贝到别的设备上下文上， */
        dc.Blit(wxPoint(0, 0), win_rect.GetSize(), &memDC, wxPoint(0, 0));
        memDC.SelectObject(wxNullBitmap);
    }

    /**
     * 初始化frame
     */
    void initFrame(){
        //默认情况下，当窗口大小改变时，只有那些需要重画的地方才会被更新，指定wx-
        //FULL REPAINT ON RESIZE窗口类型可以覆盖这种默认情况以使得整个窗口都被刷新
        wxFULL_REPAINT_ON_RESIZE;

        wxImage::AddHandler(new wxJPEGHandler);
        wxImage::AddHandler(new wxPNGHandler);
        //设置窗口位置
        wxPoint position;
        position.x = 300;
        position.y = 300;
        SetPosition(position);
        //设置背景色
        //wxColour backGroundColor(100,100,0);
        //this->SetBackgroundColour(backGroundColor);
        //设置宽高
        this->m_minWidth = 800;
        this->m_minHeight = 600;
    }

public:
    explicit MemDcFrame(wxString & title):wxFrame(nullptr, wxID_ANY, title)
    {
        this->initFrame();
    }
    ~MemDcFrame() override{
        cout << "~MemDcFrame" << endl;
    };

};

//事件和函数绑定
wxBEGIN_EVENT_TABLE(MemDcFrame, wxFrame)
                EVT_PAINT(MemDcFrame::OnPaint_)
wxEND_EVENT_TABLE()

/**
 * app
 */
class MemDcApp:public wxApp
{
    bool OnInit()override
    {
        wxString title = wxT("MemoryDc绘制");
        //  wxFrame * frame = new wxFrame(NULL, wxID_ANY, "第一个窗体");
        auto * frame = new MemDcFrame(title);
        frame->Show();
        cout << "OnInit"<< endl;
        return true;
    }
};


// 有了这一行就可以使用 OurApp& wxGetApp了()
DECLARE_APP(MemDcApp)
//告诉主应用程序是哪个类wxWidgets（启动）
//IMPLEMENT_APP(MemDcApp)
